"""
OpenGauss 数据库模式编辑器
处理数据库模式的创建、修改和删除操作
"""
import re

from django.db.backends.postgresql import schema as postgresql_schema
from django.db.backends.ddl_references import Statement
from django.db import models


class DatabaseSchemaEditor(postgresql_schema.DatabaseSchemaEditor):
    """
    OpenGauss 数据库模式编辑器
    继承自 PostgreSQL，针对 OpenGauss 特性进行优化
    """
    
    # SQL 模板
    sql_create_sequence = "CREATE SEQUENCE %(sequence)s"
    sql_delete_sequence = "DROP SEQUENCE IF EXISTS %(sequence)s CASCADE"
    sql_set_sequence_max = "SELECT setval('%(sequence)s', MAX(%(column)s)) FROM %(table)s"
    sql_alter_column_type = "ALTER TABLE %(table)s ALTER COLUMN %(column)s TYPE %(type)s USING %(column)s::%(type)s"
    
    # OpenGauss 特有的 SQL 模板
    sql_create_index_concurrently = "CREATE INDEX CONCURRENTLY %(name)s ON %(table)s%(using)s (%(columns)s)%(extra)s"
    sql_create_unique_index = "CREATE UNIQUE INDEX %(name)s ON %(table)s (%(columns)s)%(extra)s"
    
    def __init__(self, connection, collect_sql=False, atomic=True):
        super().__init__(connection, collect_sql, atomic)
        self.sql_alter_column_collate = None  # OpenGauss 使用不同的语法
    
    def _field_data_type(self, field):
        """
        返回字段的数据类型
        针对 OpenGauss 特定类型进行映射
        """
        # 获取基础数据类型
        data_type = super()._field_data_type(field)
        
        # OpenGauss 特定类型映射
        if isinstance(field, models.JSONField):
            # OpenGauss 推荐使用 JSONB 获得更好的性能
            return 'JSONB'
        elif isinstance(field, models.TextField) and getattr(field, 'db_collation', None):
            # 处理带排序规则的文本字段
            return data_type + ' COLLATE "%s"' % field.db_collation
        
        return data_type
    
    def column_sql(self, model, field, include_default=False):
        """
        返回字段的完整列定义 SQL
        修复 serial 字段的 PRIMARY KEY 重复问题
        """
        # 获取基本的列 SQL
        column_result = super().column_sql(model, field, include_default)
        
        # column_sql 返回的是 (sql, params) 元组
        if isinstance(column_result, tuple):
            column_sql, params = column_result
        else:
            column_sql, params = column_result, []
        
        # 如果是自增字段且已经包含 PRIMARY KEY，则移除重复的
        if (hasattr(field, 'primary_key') and field.primary_key and 
            isinstance(field, (models.AutoField, models.BigAutoField, models.SmallAutoField))):
            # OpenGauss 使用 serial/bigserial，避免额外的 IDENTITY 子句
            column_sql = re.sub(r'\s*GENERATED (ALWAYS|BY DEFAULT) AS IDENTITY', '', column_sql, flags=re.IGNORECASE)
            
        return column_sql, params
    
    def prepare_default(self, value):
        """
        准备默认值
        处理 OpenGauss 特定的默认值格式
        """
        if isinstance(value, (dict, list)):
            # JSON 类型的默认值
            return self.quote_value(self.connection.ops.adapt_json_value(value, None))
        return super().prepare_default(value)
    
    def execute(self, sql, params=()):
        """
        执行 SQL 语句
        添加 OpenGauss 特定的错误处理
        """
        try:
            # 在 OpenGauss 上移除 Django 生成的 IDENTITY 子句
            if isinstance(sql, str):
                sql = re.sub(r'GENERATED (ALWAYS|BY DEFAULT) AS IDENTITY', '', sql, flags=re.IGNORECASE)
                sql = re.sub(r'TYPE\s+bigserial', 'TYPE bigint', sql, flags=re.IGNORECASE)
                sql = re.sub(r'TYPE\s+serial', 'TYPE integer', sql, flags=re.IGNORECASE)
                sql = re.sub(r'::bigserial', '::bigint', sql, flags=re.IGNORECASE)
                sql = re.sub(r'::serial', '::integer', sql, flags=re.IGNORECASE)
                if re.match(r'\s*ALTER\s+SEQUENCE\b[^;]*$', sql, flags=re.IGNORECASE):
                    # OpenGauss 兼容性：无需调整序列类型，直接跳过
                    return
            super().execute(sql, params)
        except Exception as e:
            # 处理 OpenGauss 特定的错误
            error_message = str(e)
            if "already exists" in error_message:
                # 对象已存在，可能需要特殊处理
                if self.collect_sql:
                    # 收集 SQL 模式下忽略错误
                    pass
                else:
                    raise
            else:
                raise
